#!/usr/bin/python
#coding: utf-8
import ConfigParser
import sys
import glob
import os
import re
import time
from lxml import etree
from pykml import parser
from pykml.factory import  KML_ElementMaker as KML
from pykml.factory import GX_ElementMaker as GX

class kmlBee(object):
    """
    kml tools
    1. convert scope
    2. read kml
    3. extract element
    4. create new kml
    """

    def __init__(self, version, kmltype, scope_section):
        SUPPORTED_TYPE = ['lane', 'paint', 'avslam' , 'sign']
        self.version = version
        if kmltype in SUPPORTED_TYPE:
            self.kmltype = kmltype
        else:
            print '%s is not support..' %kmltype
            sys.exit(1)
        self.conf_base = os.getcwd() + '/conf/'
        self.conf_ini = self.conf_base + 'config.ini'
        self.color = self.conf_parser(self.version, 'color')
        self.scope = {}
        self.converted_scope = {}
        self.kmlcontent = ''
        self.extracted_elements = []
        self.filtered_elements = []
        #self.new_content = KML.kml()
        self.outkml = ''
        self.new_kml = KML.kml()
        self.scope_section = scope_section

    def conf_parser(self, section, option):
        cf = ConfigParser.ConfigParser()
        cf.read(self.conf_ini)
        res = cf.get(section, option)
        return res

    def get_outkml(self):
        return self.outkml

    def get_scope(self):
        scope_file = self.conf_base + 'scope.txt'
        cf = ConfigParser.ConfigParser()
        cf.read(scope_file)
        scope = {}
        scope['east'] = cf.get(self.scope_section, 'EAST')
        scope['west'] = cf.get(self.scope_section, 'WEST')
        scope['north'] = cf.get(self.scope_section, 'NORTH')
        scope['south'] = cf.get(self.scope_section, 'SOUTH')
        self.scope = scope

    def convert_scope(self):
        converted_scope = {}
        for key in self.scope.keys():
            x = re.split("°|'|\"", self.scope[key])[:3]
            x = map(float, x)
            converted_scope[key] = round((x[0] + x[1] / 60 + x[2] / 3600), 14)
        self.converted_scope = converted_scope
        return converted_scope

    def _open_kml(self):
        kmlfile = glob.glob(os.getcwd() + '/kml/{}/{}*.kml'.format(self.version,
                                                                   self.conf_parser('general', self.kmltype)))[0]
        with open(kmlfile) as f:
            doc = parser.parse(f)
        return doc

    def extract_elements(self):
        kmlcont = self._open_kml()
        element = ''
        if self.kmltype == 'lane':
            element = 'Placemark'
        elif self.kmltype == 'paint':
            element = 'LineString'
        elif self.kmltype == 'sign':
            element = 'Placemark'
        elif self.kmltype == 'rawslam':
            pass
        elif self.kmltype == 'avgps':
            pass
        elif self.kmltype == 'avslam':
            element = 'LineString'
        self.extracted_elements = kmlcont.xpath('.//kml:{}'.format(element),
                                  namespaces={'kml': 'http://earth.google.com/kml/2.2'})
        return self.extracted_elements

    def filter_elements(self):
        for element in self.extracted_elements:
            coordinates = element.xpath('.//kml:coordinates/text()',
                                  namespaces={'kml': 'http://earth.google.com/kml/2.2'})[0]
            inscope = self._filter_element(str(coordinates))
            if inscope:
                self.filtered_elements.append(element)
        return self.filtered_elements

    def _filter_element(self, element):
        inscope = 1
        for line in element.split('\n'):
            if line.strip():
                x = map(float, line.split(','))
                if x[0] > self.converted_scope['west'] \
                        and x[0] < self.converted_scope['east'] \
                        and x[1] > self.converted_scope['south'] \
                        and x[1] < self.converted_scope['north']:
                    pass
                else:
                    inscope = 0
        return inscope

    def generate_kml(self):
        if self.kmltype == 'lane':
            doc = self.generate_lane_kml()
        elif self.kmltype == 'avslam' or \
            self.kmltype == 'paint':
            doc = self.generate_avslam_paint_kml()
        elif self.kmltype == 'sign':
            doc = self.generate_sign_kml()
        self.new_kml = doc
        return doc


    def generate_avslam_paint_kml(self):
        docbase = KML.kml(
            KML.Document(
                KML.Style(
                    KML.LineStyle(
                        KML.color(self.color),
                        KML.width('4')
                    ),
                    id='RoadMark',
                ),
                KML.Placemark(
                    KML.styleUrl('#RoadMark'),
                    KML.MultiGeometry(
                        KML.name('rdb-multigeometry')


                    )
                )
            )
        )
        for item in self.filtered_elements:
            pm_coord = item.xpath('.//kml:coordinates/text()',
                                  namespaces={'kml': 'http://earth.google.com/kml/2.2'})[0]
            pm = KML.LineString(
                KML.coordinates(pm_coord)
            )
            docbase.Document.Placemark.MultiGeometry.append(pm)
        return docbase

    def generate_lane_kml(self):
        self.color = self.conf_parser(self.version,'color')
        docbase = KML.kml(
            KML.Document(
                KML.Style(
                    KML.LineStyle(
                        KML.color(self.color),
                        KML.width('4')

                    ),
                    id='RoadMark',
                ),
                id='new_generated',
            )
        )
        pm_base = KML.Folder(
            KML.name('Road Marks')
        )
        for item in self.filtered_elements:
            pm_name = item.xpath('.//kml:name/text()',
                                 namespaces={'kml': 'http://earth.google.com/kml/2.2'})[0]
            pm_desc = item.xpath('.//kml:description/text()',
                                 namespaces={'kml': 'http://earth.google.com/kml/2.2'})[0]
            pm_styleurl = item.xpath('.//kml:styleUrl/text()',
                                     namespaces={'kml': 'http://earth.google.com/kml/2.2'})[0]
            pm_altitudeMode = item.xpath('.//kml:altitudeMode/text()',
                                         namespaces={'kml': 'http://earth.google.com/kml/2.2'})[0]
            pm_coord = item.xpath('.//kml:LineString/kml:coordinates/text()',
                                  namespaces={'kml': 'http://earth.google.com/kml/2.2'})[0]
            pm = KML.Placemark(
                KML.name(pm_name),
                KML.description(pm_desc),
                KML.styleUrl(pm_styleurl),
                KML.altitudeMode(pm_altitudeMode),
                KML.LineString(
                    KML.coordinates(pm_coord),
                )

            )
            pm_base.append(pm)
        docbase.Document.append(pm_base)
        return docbase

    def generate_sign_kml(self):
        docbase = KML.kml(
            KML.Document(
                KML.Style(
                    KML.IconStyle(
                        KML.color('ff00ffff'),
                        KML.scale(0.5),
                        KML.Icon(
                            KML.href('http://maps.google.com/mapfiles/kml/shapes/shaded_dot.png')
                        )
                    ),
                    KML.ListStyle(),
                    id = "sn_placemark_circle",
                ),
                KML.Style(
                    KML.IconStyle(
                        KML.color('#ffff0000'),
                        KML.scale(0.5),
                        KML.Icon(
                            KML.href('http://maps.google.com/mapfiles/kml/shapes/shaded_dot.png')
                        )
                    ),
                    KML.ListStyle(),
                    id = "sn_placemark_circle_highlight",
                ),
                KML.StyleMap(
                    KML.Pair(
                        KML.key('normal'),
                        KML.styleUrl('#sn_placemark_circle')
                    ),
                    KML.Pair(
                        KML.key('highlight'),
                        KML.styleUrl('#sn_placemark_circle_highlight')
                    )
                ),
                KML.Folder(
                    KML.name('Traffic Signs')
                )
            )
        )
        for item in self.filtered_elements:
            pm_name = item.xpath('.//kml:name/text()',
                                 namespaces={'kml': 'http://earth.google.com/kml/2.2'})[0]
            pm_desc = item.xpath('.//kml:description/text()',
                                 namespaces={'kml': 'http://earth.google.com/kml/2.2'})[0]
            pm_styleurl = item.xpath('.//kml:styleUrl/text()',
                                     namespaces={'kml': 'http://earth.google.com/kml/2.2'})[0]
            pm_altitudeMode = item.xpath('.//kml:altitudeMode/text()',
                                         namespaces={'kml': 'http://earth.google.com/kml/2.2'})[0]
            pm_coord = item.xpath('.//kml:coordinates/text()',
                                  namespaces={'kml': 'http://earth.google.com/kml/2.2'})[0]
            pm = KML.Placemark(
                KML.name(pm_name),
                KML.description(pm_desc),
                KML.altitudeMode(pm_altitudeMode),
                KML.styleUrl(pm_styleurl),
                KML.Point(
                    GX.drawOrder(1),
                    KML.coordinates(pm_coord),
                )
            )
            docbase.Document.Folder.append(pm)
        return docbase


    def save_kml(self):
        kmlname = self.conf_parser('general', self.kmltype)
        output_kml_base = kmlname 
        output_kml = './results/out/' + output_kml_base + self.scope_section.replace(' ', '-') + '.kml'
        self.outkml = output_kml
        print output_kml
        file(output_kml, 'w').write(etree.tostring(self.new_kml, pretty_print=True))
        return output_kml
